#include "boot_update.h"
#include "gd32f4xx.h"
#include "gd32f4xx_fmc.h"
#include "gd32f4xx_usart.h"
#include "gd32f4xx_gpio.h"
#include "gd32f4xx_rcu.h"
#include "led.h"
#include "usart.h"
#include "crc.h"
#include <string.h>

/* 使用at属性指定地址，used确保不被优化掉，const确保只能读不能写 */
volatile const device_info_t device_info __attribute__((section(".device_info"))) __attribute__((used)) = {
    .app_valid_flag = 0,
    .app_size = 0,
    .app_crc = 0,
    .app_version = 0x01000000, // 版本1.0.0.0
    .device_id = {0},
    .reserve = {0}};

// update_state_t update_state = UPDATE_STATE_IDLE;
bool write_flash_data(uint8_t *data, uint16_t length)
{
    static uint32_t write_addr = APP_ADDR; // APP起始地址
    fmc_state_enum status;
    uint32_t *word_data = (uint32_t *)data;
    uint32_t word_count = (length + 3) / 4; // 向上取整到字对齐

    // 解锁Flash
    fmc_unlock();

    // 清除所有标志位
    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR |
                   FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);

    // 按字写入数据
    for (uint32_t i = 0; i < word_count; i++)
    {
        status = fmc_word_program(write_addr, word_data[i]);
        if (status != FMC_READY)
        {
            fmc_lock();
            return false;
        }

        // 验证写入
        if (*(uint32_t *)write_addr != word_data[i])
        {
            fmc_lock();
            return false;
        }

        write_addr += 4;
    }

    // 锁定Flash
    fmc_lock();
    return true;
}

// 固件验证函数
bool verify_firmware(void)
{
    uint32_t app_size = *(uint32_t *)APP_SIZE_ADDR; // 从固定地址读取固件大小
    uint32_t checksum = 0;

    // 计算固件校验和
    for (uint32_t addr = APP_ADDR; addr < APP_ADDR + app_size; addr += 4)
    {
        checksum += *(uint32_t *)addr;
    }

    // 与存储的校验和比较
    return (checksum == *(uint32_t *)APP_CHECKSUM_ADDR);
}
// 串口缓冲区定义(全局变量)
uart_buffer_t uart_buf = {0};

// 供中断使用的缓冲区写入函数
uint8_t uart_buf_write(uint8_t data)
{
    uint8_t next = (uart_buf.wr_index + 1) % FRAME_MAX_SIZE;
    if (next != uart_buf.rd_index)
    {
        uart_buf.buf[uart_buf.wr_index] = data;
        uart_buf.wr_index = next;
        return 1; // 写入成功
    }
    return 0; // 缓冲区满
}
// 发送数据帧
uint8_t send_frame(frame_t *frame)
{
    const static uint8_t min_frame_size = MIN_FRAME_SIZE; // SOF(1) + CMD(1) + LENGTH(1) + CRC(2)

    if (uart_tx_manager.busy != 0)
    {
        return 0;
    }
    if (frame->length > FRAME_MAX_SIZE - min_frame_size)
    {
        return 1;
    }
    uart_tx_manager.busy = 1;
    uart_tx_manager.buf[0] = frame->sof;
    uart_tx_manager.buf[1] = frame->cmd;
    uart_tx_manager.buf[2] = frame->length;
    memcpy(uart_tx_manager.buf + 3, frame->data, frame->length);
    uart_tx_manager.buf[frame->length + 3] = crc8(uart_tx_manager.buf + 3, frame->length);
    uart_tx_manager.buf_size = frame->length + 4;
    uart0_send_data(uart_tx_manager.buf, uart_tx_manager.buf_size);
    return 1;
}

/**
 * @brief  从接收缓冲区中解析帧
 * @param  uart: 串口管理结构体指针
 * @param  frame: 解析后的帧结构体指针
 * @retval 0: 解析失败, 1: 解析成功
 */
uint8_t parse_uart_buffer_to_frame(uart_manager_t *uart, frame_t *frame)
{
    const static uint16_t min_frame_size = MIN_FRAME_SIZE; // SOF(1) + CMD(1) + LENGTH(1) + CRC(2)

    // 检查缓冲区中是否有足够的数据
    if (uart->buf_size < min_frame_size)
    {
        return 0; // 数据不足
    }

    if (uart->buf[0] != FRAME_SOF)
    {
        return 0; // 帧头错误
    }
    uint8_t data_length = uart->buf[2];
    if (data_length > FRAME_MAX_SIZE - min_frame_size || data_length != uart->buf_size - min_frame_size)
    {
        return 0; // 数据长度错误
    }

    if (crc8(uart->buf + 3, data_length) != uart->buf[data_length + 3])
    {
        return 0; // CRC校验失败
    }
    frame->sof = uart->buf[0];
    frame->cmd = uart->buf[1];
    frame->length = uart->buf[2];
    frame->crc = uart->buf[data_length + 3];
    memcpy(frame->data, uart->buf + 3, data_length);
    return 1; // 解析成功
}

void boot_update(void)
{
}

void update_init(void)
{
    usart0_dma1_init();
    led_on(LED1);
    led_on(LED2);
    led_on(LED3);
    led_on(LED4);
}
// 处理接收到的帧
static void process_frame(frame_t *frame)
{
    switch (frame->cmd)
    {
    case CMD_UPDATE:
    {
        frame->length = 0;
        boot_update();
        break;
    }
    default:
        break;
    }
}
// 数据处理
void update_process(void)
{
    if (uart_rx_manager.busy != 0)
    {
        return;
    }
    frame_t frame;
    if (parse_uart_buffer_to_frame(&uart_rx_manager, &frame))
    {
        process_frame(&frame);
    }
    else
    {
        frame.cmd |= 0x80;
    }
    send_frame(&frame);
}

/*!
    \brief      检查应用程序是否有效
    \param[in]  app_addr: 应用程序起始地址
    \retval     1: 有效, 0: 无效
*/
uint8_t check_app_valid(void)
{
    volatile const device_info_t *info = (device_info_t *)DEVICE_INFO_ADDR;
    uint32_t reset_flags = RCU_RSTSCK;
    uint32_t app_addr = APP_CODE_OFFSET; // APP起始地址，如0x08008000

    // 1. 清除复位标志
    RCU_RSTSCK |= RCU_RSTSCK_RSTFC;

    // 2. 检查设备信息有效性
    if (info->app_valid_flag != APP_VALID_FLAG)
    {
        return 0; // APP标志无效
    }

    // 3. 检查APP程序入口点有效性
    uint32_t *vectors = (uint32_t *)app_addr;
    uint32_t sp = vectors[0]; // 栈顶地址
    uint32_t pc = vectors[1]; // 程序计数器（复位向量）

    // 检查栈顶指针是否在RAM范围内
    if (sp < SRAM_BASE || sp > (SRAM_BASE + SRAM_SIZE))
    {
        return 0;
    }

    // 检查程序入口点是否在Flash范围内
    if (pc < APP_CODE_OFFSET || pc >= (FLASH_BASE + FLASH_SIZE))
    {
        return 0;
    }

    // 4. 根据复位源处理
    if (reset_flags & RCU_RSTSCK_SWRSTF)
    {
        return 1; // 正常软件复位，运行APP
    }

    if (reset_flags & RCU_RSTSCK_PORRSTF)
    {
        // 上电复位
        return 1; // 运行APP
    }

    if (reset_flags & RCU_RSTSCK_EPRSTF)
    {
        // 外部复位引脚复位
        return 1; // 运行APP
    }

    // 其他复位源
    return 1; // 默认运行APP
}

/*!
    \brief      跳转到应用程序执行
    \param[in]  none
    \param[out] none
    \retval     none
*/
void execute_user_code(void)
{
    uint32_t JumpAddress;

    /* 关闭所有外设 */
    usart_deinit(USART0);
    // gpio_deinit(LED_GPIO_PORT);
    rcu_deinit();

    /* 设置主堆栈指针 */
    __set_MSP(*(__IO uint32_t *)APP_CODE_OFFSET);
    SCB->VTOR = APP_CODE_OFFSET; // 设置为0x08008000
    __enable_irq();
    JumpAddress = *(__IO uint32_t *)(APP_CODE_OFFSET + 4);
    /* 跳转到应用程序 */
    ((void (*)(void))JumpAddress)();
}